package com.taritari.journal.services;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.taritari.journal.entity.dto.JournalAddDto;
import com.taritari.journal.entity.dto.JournalsDto;
import com.taritari.journal.entity.dto.SentimentMqDto;
import com.taritari.journal.entity.po.Journals;
import com.taritari.journal.entity.vo.JournalDetailVo;
import com.taritari.journal.entity.vo.JournalsVo;
import com.taritari.journal.entity.vo.TaskInfoItem;
import com.taritari.journal.entity.vo.TodayJournalVo;
import com.taritari.journal.enums.ResultCode;
import com.taritari.journal.mapper.JournalsMapper;
import com.taritari.journal.services.impl.JournalsServiceImpl;
import com.taritari.journal.utils.DateUtil;
import com.taritari.journal.utils.Result;
import io.netty.util.internal.StringUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 日记service
 * */
@Slf4j
@Service
public class JournalsService extends ServiceImpl<JournalsMapper, Journals> implements JournalsServiceImpl {
    @Autowired
    private JournalsMapper journalsMapper;
    @Autowired
    private DateUtil dateUtil;
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 获取主页日记列表
     * */
    public JournalsDto getJournalByAuthorId(int authorId, int currentPage) {
        // 先查询该用户写的日记月份的统计
        List<Integer> months = journalsMapper.selectMonthByAuthorId(authorId);
        //排序
        if (months != null && !months.isEmpty()) {
            List<Integer> sortedMonths = months.stream()
                    .sorted((month1, month2) -> month2.compareTo(month1)) // 从大到小排序
                    .collect(Collectors.toList());

            if (currentPage>=sortedMonths.size()){
                return null;
            }
            // 在这里使用 sortedMonths 进行其他操作
            Integer month = sortedMonths.get(currentPage);
            // 获取全部日记列表，按照 createTime 字段降序排序
            List<Journals> allJournals = journalsMapper.selectList(
                    new LambdaQueryWrapper<Journals>()
                            .eq(Journals::getAuthorId, authorId)
                            .eq(Journals::getIsDelete, 0)
                            .eq(Journals::getMonth,month)
                            .orderByDesc(Journals::getCreateTime));
            //获取中文日记名-通过枚举对应查询然后主页用
            String chineseMonth = dateUtil.monthFormat(month);
            JournalsDto journalsDto = new JournalsDto();
            journalsDto.setMonth(chineseMonth);
            List<JournalsVo> journalsVos = new ArrayList<>();
            //每个月的具体日记
            for (Journals journal : allJournals) {
                JournalsVo journalsVo = new JournalsVo();
                // Extract time, date, and day of the week
                Date createTime = journal.getCreateTime();
                // Format time
                String time = dateUtil.timeFormat(createTime);
                // Format date
                String date = dateUtil.dateFormat(createTime);
                // format day
                String dayOfMonth = dateUtil.dayFormat(createTime);
                // Get day of the week
                String weekDay = dateUtil.weekFormat(createTime);


                journalsVo.setId(journal.getId());
                journalsVo.setContent(journal.getIntro());
                journalsVo.setDate(journalsVo.getDate());
                journalsVo.setTime(time);
                journalsVo.setDate(date);
                journalsVo.setDay(dayOfMonth);
                journalsVo.setWeek(weekDay);
                journalsVos.add(journalsVo);
            }
            journalsDto.setData(journalsVos);
            return journalsDto;

        } else {
            // 处理空列表的逻辑
            System.out.println("月份列表为空");
            return null;
        }

    }
    /**
     * 通过id获取日记详情
     * */
    @Override
    public JournalDetailVo getJournalInfoById(int id) {
        //查询
        Journals journals = journalsMapper.selectById(id);
        JournalDetailVo journalDetailVo = new JournalDetailVo();
        // 赋值
        journalDetailVo.setJournalContent(journals.getContent());
        Date createTime = journals.getCreateTime();
        journalDetailVo.setTime(dateUtil.timeFormat(createTime));
        journalDetailVo.setWeek(dateUtil.weekFormat(createTime));
        journalDetailVo.setDay(dateUtil.dayFormat(createTime));
        journalDetailVo.setYear(dateUtil.yearFormat(createTime));
        journalDetailVo.setMonth(dateUtil.monthFormat(journals.getMonth()));
        journalDetailVo.setNumber(journals.getNumber());
        journalDetailVo.setTitle(journals.getIntro());
        return journalDetailVo;
    }
    // 模拟异步函数，将图片路径转换为Base64
    private static String pathToBase64(String imagePath) {
        try {
            // 下载图片到临时文件
            URL url = new URL(imagePath);
            Path tempFile = Files.createTempFile("tempImage", ".png");
            Files.copy(url.openStream(), tempFile, StandardCopyOption.REPLACE_EXISTING);

            // 读取临时文件内容并转换为Base64字符串
            byte[] fileBytes = Files.readAllBytes(tempFile);
            return Base64.getEncoder().encodeToString(fileBytes);
        } catch (IOException e) {
            e.printStackTrace();
            return "";  // 处理异常时返回空字符串，你可以根据实际情况进行适当的处理
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 分享日记涉及的一些格式转换
     * */
    public JournalDetailVo getShareJournal(int id) {
        JournalDetailVo journalInfoById = getJournalInfoById(id);
        // 使用正则表达式匹配所有的src标签
        String SRC_REGEX = "src=\"([^\"]*)\"";
        Pattern SRC_PATTERN = Pattern.compile(SRC_REGEX);
        // 使用正则表达式匹配所有的src标签
        Matcher matcher = SRC_PATTERN.matcher(journalInfoById.getJournalContent());

        // 对每个匹配到的src标签进行替换
        StringBuffer resultBuffer = new StringBuffer();
        while (matcher.find()) {
            String srcUrl = matcher.group(1);
            String newBase64 = pathToBase64(srcUrl);
            matcher.appendReplacement(resultBuffer, "src=\"data:image/jpeg;base64," + newBase64 + "\"");
        }
        matcher.appendTail(resultBuffer);

        // 输出替换后的字符串
        String replacedContent = resultBuffer.toString();
        journalInfoById.setJournalContent(replacedContent);
        return journalInfoById;

    }
    /**
     * 获取用户日记写作情况
     * @param dateList 日期list
     * @param id 用户id
     * */
    @Override
    public Result selectUserWritingThisMonth(List<String> dateList, int id) {
        List<String> journalDays = new ArrayList<>();
        // 获取每个日期是否写过日记
        if (!dateList.isEmpty()){
            dateList.forEach(date->{
                Integer count = journalsMapper.isJournalByDate(date, id);
                if (count>0){
                    // 存在日记在加入列表
                    journalDays.add(date);
                }
            });
        }else {
            return Result.fail(ResultCode.QUERY_EMPTY);
        }
        return Result.success(journalDays);
    }
    /**
     * 通过日期获取日记详情
     * */
    @Override
    public Result selectJournalDetailByDate(String date, int id) {
        //查询
        Journals journals = journalsMapper.selectJourNalByDate(date, id);
        if (BeanUtil.isNotEmpty(journals)){
            // 不为空，赋值
            JournalsVo journalsVo = new JournalsVo();
            journalsVo.setId(journals.getId());
            journalsVo.setContent(journals.getIntro());
            Date createTime = journals.getCreateTime();
            journalsVo.setDate(dateUtil.dateFormat(createTime));
            journalsVo.setTime(dateUtil.timeFormat(createTime));
            journalsVo.setDay(dateUtil.dayFormat(createTime));
            journalsVo.setWeek(dateUtil.weekFormat(createTime));
            journalsVo.setTime(dateUtil.timeFormat(createTime));
            return Result.success(journalsVo);
        }else {
            return Result.fail(ResultCode.QUERY_EMPTY);
        }

    }
    /**
     * 添加日记
     * */
    @Override
    public Result addJournal(JournalAddDto journalAddDto) {
        //先查询是否有写日记 返回日记编号
        String number = journalsMapper.queryIsJournalByDate(Integer.parseInt(journalAddDto.getId()), journalAddDto.getDate());
        try {
            // 在给日记实体类赋值
            Journals journals = new Journals();
            journals.setIntro(journalAddDto.getTitle());
            journals.setContent(journalAddDto.getHtml());
            journals.setAuthorId(Integer.parseInt(journalAddDto.getId()));
            journals.setMonth(dateUtil.getMonth(journalAddDto.getDate()));
            journals.setCreateTime(cn.hutool.core.date.DateUtil.date());
            journals.setWordCount(journalAddDto.getText().length());
            journals.setJournalDate(cn.hutool.core.date.DateUtil.parseDate(journalAddDto.getDate()));
           // 日记源格式传入，转为json后续加入数据库
            if (ObjectUtil.isNotEmpty(journalAddDto.getTaskinfodtv())){
                List<Map<String, String>> taskinfodtv = journalAddDto.getTaskinfodtv();
                String jsonString = JSONObject.toJSONString(taskinfodtv);
                journals.setTaskinfodtv(jsonString);
            }
            //不存在日记，执行添加
            if (StringUtil.isNullOrEmpty(number)){
                number = RandomUtil.randomNumbers(14);
                // 随机生成的number
                journals.setNumber(number);
                int insert = journalsMapper.insert(journals);
                // mq重新获取情感趋势
                mqAdd(number,journalAddDto);
                return Result.success(insert);
            }else {//存在日记，执行修改
                LambdaQueryWrapper<Journals> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Journals::getNumber,number);
                // 原来的number
                journals.setNumber(number);
                int update = journalsMapper.update(journals, queryWrapper);
                // mq重新获取情感趋势
                mqAdd(number,journalAddDto);
                return Result.success(update);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    /**
     * rabbitmq的生产者
     * @param number 日记number
     * */
    private void mqAdd(String number,JournalAddDto journalAddDto){
        //mq异步分析情感趋势
        SentimentMqDto sentimentMqDto = new SentimentMqDto();
        sentimentMqDto.setNumber(number);
        sentimentMqDto.setAuthorId(journalAddDto.getId());
        sentimentMqDto.setText(journalAddDto.getText());
        sentimentMqDto.setData(journalAddDto.getDate());
        String jsonString = JSON.toJSONString(sentimentMqDto);
        // 交换机名
        String exchangeName = "journal_sentiment";
        //路由名，由交换机绑定
        String routingKey = "sentiment";
        rabbitTemplate.convertAndSend(exchangeName,routingKey,jsonString);
        //延时方法

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                rabbitTemplate.convertAndSend(exchangeName,routingKey,jsonString);
                this.cancel();
            }
        }, 3000);

    }
    /**
     * 通过日期获取当天的日记
     * 提那家日记的时候用
     * */
    @Override
    public TodayJournalVo queryTodayJournal(int id, String date) {
        TodayJournalVo todayJournalVo = journalsMapper.queryOneByJournalDate(id, date);
        if (BeanUtil.isNotEmpty(todayJournalVo)){
            String taskinfodtv = todayJournalVo.getTaskinfodtv();
            // 改变日记源格式，前端进行展示
            List<TaskInfoItem> taskInfoItems = JSON.parseArray(taskinfodtv, TaskInfoItem.class);
            todayJournalVo.setOrigin(taskInfoItems);
            return todayJournalVo;
        }else {
            return null;
        }
    }
    /**
     * 通过id获取日记源数据-修改用
     * */
    @Override
    public TodayJournalVo queryJournalByDate(int id, int authorId) {
        TodayJournalVo todayJournalVo = journalsMapper.queryJournalByDate(id, authorId);
        if (BeanUtil.isNotEmpty(todayJournalVo)){
            String taskinfodtv = todayJournalVo.getTaskinfodtv();
            // 改变日记源格式，前端进行展示
            List<TaskInfoItem> taskInfoItems = JSON.parseArray(taskinfodtv, TaskInfoItem.class);
            todayJournalVo.setOrigin(taskInfoItems);
            return todayJournalVo;
        }else {
            return null;
        }
    }
    /**
     * 通过id删除日记
     * is_delete = 1
     * */
    @Override
    public int deleteJournalById(int id) {
        int res = journalsMapper.deleteJournalById(id);
        return res;
    }
    /**
     * 查询指定用户的前三篇日记
     * authorId 用户id
     * */
    @Override
    public  Map<String,Object> getThreeJournal(int authorId) {
        List<Journals> journals = journalsMapper.queryThreeJournalByAuthorId(authorId);
        journals.forEach(item -> {
            String taskinfodtv = item.getTaskinfodtv();
            JSONArray jsonArray = JSONArray.parseArray(taskinfodtv);

            JSONObject jsonObject = jsonArray.getJSONObject(0);
            String value = jsonObject.getString("value");
            item.setTaskinfodtv(value);
        });
        Map<String,Object> map = new HashMap<>();
        List<Map<String,String>> listMap = new LinkedList<>();
        List<String> datalist = new LinkedList<>();
        if ( journals.size() > 0){
            for (Journals item : journals) {
                Map<String,String> maps = new HashMap<>();
                String info = item.getTaskinfodtv().replaceAll("\\n","");
                maps.put("title",item.getIntro());
                datalist.add(info);
                listMap.add(maps);
            }
            map.put("list",listMap);
            map.put("data",datalist);

        }
        return map;
    }


}
